import datetime
import hashlib
import io
import json
import logging
import os
import shutil
import uuid

import minio
import pandas as pd
import xlsxwriter

from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect
from django.template.loader import render_to_string

from share_report import settings
from . import utils
from .forms import UploadFileForm, MoldLogForm
from io import BytesIO

from .models import MoldLog, FileMoldLog

logger = logging.getLogger('django')
MINIO_SERVER = '10.101.0.178:9000'


# 生成响应
def make_response(status=200, content_type='text/plain', content=None):
    """ Construct a response to an upload request.
    Success is indicated by a status of 200 and { "success": true }
    contained in the content.

    Also, content-type is text/plain by default since IE9 and below chokes
    on application/json. For CORS environments and IE9 and below, the
    content-type needs to be text/html.
    """
    response = HttpResponse()
    response.status_code = status
    response['Content-Type'] = content_type
    response.content = content
    return response


def mk_html(pp):
    # 合并 主/副标题
    products = []
    for a in pp:
        for k, v in a.items():
            p = a[k]
            p_new = {}
            for p2 in p:
                k = list(p2.keys())[0]
                prefix = k
                if 'a' in p2:
                    prefix += '/' + p2['a']
                if 'b' in p2:
                    prefix += '/' + p2['b']

                p_new[prefix] = '%.2s' % p2[k]
            products.append(p_new)
    # 渲染html
    html = render_to_string('ng/partial_feedback.html', {'products': products})
    return html


def post(request):
    """
    A POST request. Validate the form and then handle the upload
    based ont the POSTed data. Does not handle extra parameters yet.
    """

    created = 0
    updated = 0
    total = 0

    form = UploadFileForm(request.POST, request.FILES)
    if form.is_valid():
        file = request.FILES['qqfile']
        # 保存到本地
        # handle_upload(file, form.cleaned_data)
        # 读文件到内存
        f = BytesIO()
        for c in file.chunks():
            f.write(c)
        df = pd.read_excel(f, header=[0, 1])
        subject = df.columns[0][0]
        df = df.droplevel(0, axis=1)
        # 删除 ‘序’
        df.drop(['序'], axis=1, inplace=True)
        # 填空 NaN
        df.fillna('', inplace=True)
        df_dict = df.to_dict(orient='records')
        total = len(df_dict)
        # 保存到数据库
        err = ''
        for d in df_dict:
            defaults = {'factory': d['工厂'], 'product': d['品名'], 'mold_no': d['号'], 'problem': d['生产问题点'],
                        'solution': d['改善内容'], 'stage': d['改善区间'], 'before': d['改善前'], 'after': d['改善后'],
                        'is_ok': d['效果判定'],
                        'comment': d['备注']}
            try:
                obj, is_created = MoldLog.objects.update_or_create(
                    factory=d['工厂'], product=d['品名'], stage=d['改善区间'],
                    defaults=defaults
                )
                if is_created:
                    created += 1

            except Exception as e:
                err = str(e)
                break
        updated = total - created

        # 输出html
        html = ''
        return make_response(content=json.dumps({'success': True, 'p': html, 'err': err,
                                                 'result': '总数：%d，创建：%d，更新：%d' % (total, created, updated)}))
    else:
        return make_response(status=400,
                             content=json.dumps({
                                 'success': False,
                                 'error': '%s' % repr(form.errors)
                             }))


def handle_upload(f, fileattrs):
    """ Handle a chunked or non-chunked upload.
    """
    logger.info(fileattrs)

    chunked = False
    dest_folder = os.path.join(settings.UPLOAD_DIRECTORY, fileattrs['qquuid'])
    dest = os.path.join(dest_folder, fileattrs['qqfilename'])

    # Chunked
    if fileattrs.get('qqtotalparts') and int(fileattrs['qqtotalparts']) > 1:
        chunked = True
        dest_folder = os.path.join(settings.CHUNKS_DIRECTORY, fileattrs['qquuid'])
        dest = os.path.join(dest_folder, fileattrs['qqfilename'], str(fileattrs['qqpartindex']))
        logger.info('Chunked upload received')

    utils.save_upload(f, dest)
    logger.info('Upload saved: %s' % dest)

    # If the last chunk has been sent, combine the parts.
    if chunked and (fileattrs['qqtotalparts'] - 1 == fileattrs['qqpartindex']):
        logger.info('Combining chunks: %s' % os.path.dirname(dest))
        utils.combine_chunks(fileattrs['qqtotalparts'],
                             fileattrs['qqtotalfilesize'],
                             source_folder=os.path.dirname(dest),
                             dest=os.path.join(settings.UPLOAD_DIRECTORY, fileattrs['qquuid'], fileattrs['qqfilename']))
        logger.info('Combined: %s' % dest)

        shutil.rmtree(os.path.dirname(os.path.dirname(dest)))


# Index
def index_view(request):
    return render(request, 'mold_log/index.html')


# 查询
def query_view(request):
    if request.method == 'POST':
        data = {'success': False}
        p = request.POST['product']
        qs = MoldLog.objects.filter(product=p)
        if qs.count() > 0:
            data['success'] = True
            html = render_to_string('mold_log/partial_report.html', {'records': qs})
            data['html'] = html
            return JsonResponse(data)
    # 表格数据
    qs = MoldLog.objects.all()
    data = [
        {
            'id': q.pk,
            'factory': q.factory,
            'product': q.product,
            'mold_no': q.mold_no,
            'problem': q.problem,
            'solution': q.solution,
            'stage': q.stage,
            'before': q.before,
            'after': q.after,
            'is_ok': q.is_ok,
            'comment': q.comment,
        } for q in qs]
    # 添加子节点显示文件
    for d in data:
        qs = FileMoldLog.objects.filter(mold_log__id=d['id'])
        d['docs'] = qs.count()

    products = MoldLog.objects.all().values('product').distinct()

    return render(request, 'mold_log/query.html', {'products': products, 'data': json.dumps(data)})


def write_excel(qs):
    output = io.BytesIO()
    workbook = xlsxwriter.Workbook(output, {'in_memory': True})

    # 格式
    bold = workbook.add_format({'bold': 1})
    cell_format = workbook.add_format()
    cell_format.set_align('left')
    cell_format.set_align('vcenter')
    cell_format.set_text_wrap()

    hidden = workbook.add_format()
    hidden.set_hidden()

    title = '模具改进日志记录'
    workbook.add_worksheet(name=title)
    worksheet = workbook.get_worksheet_by_name(title)
    # 激活工作表
    worksheet.activate()
    worksheet.set_default_row(21)  # 行高
    # worksheet.set_column('A:A', 50)
    # worksheet.set_column('B:B', 10)
    # worksheet.set_column('C:C', 300)

    worksheet.write_string('A2', '序号', bold)
    worksheet.write('B2', '工厂', bold)
    worksheet.write('C2', '品名', bold)
    worksheet.write('D2', '模具号', bold)
    worksheet.write('E2', '生产问题', bold)
    worksheet.write('F2', '改善内容', bold)
    worksheet.write('G2', '改善区间', bold)
    worksheet.write('H2', '改善前', bold)
    worksheet.write('I2', '改善后', bold)
    worksheet.write('J2', '判定效果', bold)
    worksheet.write('K2', '备注', bold)
    row = 2
    col = 0
    # 标题
    merge_format = workbook.add_format({
        'bold': True,
        'border': 6,
        'align': 'center',  # 水平居中
        'valign': 'vcenter',  # 垂直居中
        'fg_color': '#D7E4BC',  # 颜色填充
    })
    worksheet.merge_range('A1:K1', title, merge_format)
    for i, q in enumerate(qs):
        worksheet.write_number(row, col, i, cell_format)
        worksheet.write_string(row, col + 1, q.factory, cell_format)
        worksheet.write_string(row, col + 2, q.product, cell_format)
        worksheet.write_string(row, col + 3, q.mold_no, cell_format)
        worksheet.write_string(row, col + 4, q.problem, cell_format)
        worksheet.write_string(row, col + 5, q.solution, cell_format)
        worksheet.write_string(row, col + 6, q.stage, cell_format)
        worksheet.write_string(row, col + 7, q.before, cell_format)
        worksheet.write_string(row, col + 8, q.after, cell_format)
        worksheet.write_string(row, col + 9, q.is_ok, cell_format)
        worksheet.write_string(row, col + 10, q.comment, cell_format)
        row += 1

    workbook.close()
    output.seek(0)
    return output


# 导出excel
def your_excel(request):
    if request.method == 'GET':
        # month = int(request.GET['month'])
        qs = MoldLog.objects.all()
        # 生成excel
        output = write_excel(qs)
        # 输出xls文件
        '''
        # Construct a server response.
        self.send_response(200)
        self.send_header('Content-Disposition', 'attachment; filename=test.xlsx')
        self.send_header('Content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
        self.end_headers()
        self.wfile.write(output.read())
        '''
        # response = HttpResponse(content_type='application/vnd.ms-excel')
        response = HttpResponse()
        response["Content-Type"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        response['Content-Disposition'] = 'attachment;filename=模具日志.xlsx'
        response.write(output.getvalue())

        return response


# 上传详细报告
def rpt_view(request):
    pk = int(request.GET['p'])
    rpt_num = 0
    reports = []
    qs = FileMoldLog.objects.filter(mold_log__id=pk)
    if qs.count() > 0:
        reports = [{'pk': q.id, '标题': q.title, '文件': q.filename_saved, '版本': q.version} for q in qs]
        rpt_num = qs.count()
    return render(request, 'mold_log/rpt_upload.html', {'pk': pk, 'reports': reports, 'rpt_num': rpt_num})


def rpt_post(request):
    errs = ''
    need_save = False  # 需要保存

    form = UploadFileForm(request.POST, request.FILES)
    pk = request.POST['pk']
    if form.is_valid():
        file = request.FILES['qqfile']
        name, ext = file.name.split('.')
        # 保存到本地
        # handle_upload(file, form.cleaned_data)
        # 读文件到内存
        f = BytesIO()
        for c in file.chunks():
            f.write(c)

        # 计算hash
        md5 = hashlib.md5(f.getbuffer()).hexdigest()

        f.seek(0)
        raw_size = f.getbuffer().nbytes

        version = 0
        try:
            q = FileMoldLog.objects.filter(mold_log=pk).order_by('-version')  # 此改进下，且md5相同
            # 当前版本号
            if q.count() > 0:
                version = q[0].version
            q = q.filter(md5=md5)
            # md5检验，是否已存在
            if q.count() == 0:
                version += 1
                need_save = True
        except (FileMoldLog.DoesNotExist, IndexError):
            pass
        if need_save:
            # 文件名
            file_name = '%s-%s-v%d.%s' % (name, pk, version, ext)
            # 写文件到s3
            client = minio.Minio(MINIO_SERVER, access_key='minioadmin', secret_key='minioadmin', secure=False,
                                 region='us-west-1')
            if not client.bucket_exists('mold-log'):
                client.make_bucket('mold-log')

            result_of_put = client.put_object('mold-log', file_name, data=f, length=raw_size)

            print('md5:%s, etag:%s' % (md5, result_of_put.etag))
            if md5 != result_of_put.etag:
                errs = 'hash 错误'

            # 存到数据库
            obj = FileMoldLog.objects.create(
                title=name,
                filename_saved=file_name,
                md5=md5,
                version=version,
                note=request.POST['note'],
                mold_log=MoldLog.objects.get(pk=pk)
            )
        # form is valid, return
        return make_response(content=json.dumps({'success': True, 'err': [], }))
    else:
        return make_response(status=400,
                             content=json.dumps({
                                 'success': False,
                                 'error': '%s' % repr(form.errors)
                             }))


# 取文件链接
def get_file_link(request, pk):
    rec = FileMoldLog.objects.get(pk=pk)
    client = minio.Minio(MINIO_SERVER, access_key='minioadmin', secret_key='minioadmin', secure=False, region='us-west-1')
    url = client.presigned_get_object('mold-log',
                                      rec.filename_saved,
                                      expires=datetime.timedelta(hours=1),
                                      response_headers={'Content-Disposition': 'filename="%s"' % rec.title}
                                      )
    # response = HttpResponse()
    # response["Content-Type"] = "application/octet-stream;charset=utf-8"
    # response["Content-Disposition"] = "attachment; filename=%s" % url
    # response['X-Accel-Redirect'] = url
    # return response
    return redirect(url)
